package com.company.graphgetter;

import com.company.TrianglePacket;
import com.company.graph.EdgeGraph;
import com.company.graph.PowerEdge;
import com.company.logger.GetterLogger;

import java.util.*;

public class EdgeGetterWithGraph implements GraphGetter {
    EdgeGraph G;
    HashSet<Integer> marked;
    HashMap<Integer, Integer> nodeCountRecorder;
    HashMap<Integer, Integer> edgeCountRecorder;
    List<TrianglePacket> triangleNodeRankList;
    List<TrianglePacket> triangleEdgeRankList;
    int triangleCounter = 0;

    public EdgeGetterWithGraph(EdgeGraph graph) {
        G = graph;
        marked = new HashSet<>();
        nodeCountRecorder = new HashMap<>();
        edgeCountRecorder = new HashMap<>();
        triangleNodeRankList = new ArrayList<>();
        triangleEdgeRankList = new ArrayList<>();
        int top = 0;
        int bottom = G.adjectives().size();
        GetterLogger logger = new GetterLogger();
        for (PowerEdge edgeVW : G.adjectives()) {
            int v = edgeVW.getV();
            int w = edgeVW.getW();
            List<PowerEdge> wList = G.adj(w);
            top++;
            float progress = ((float) top) / bottom * 100;
            logger.log(progress);
            for (PowerEdge edgeWP : wList) {
                int p = edgeWP.other(w);
                PowerEdge edgeVP = G.getEdge(v, p);
                if (edgeVP != null) {
                    /**
                     * 是否可以优化查找算法 对List进行遍历查找实在不是一个好办法
                     */
                    /**
                     * 更新每个节点记录的三角形个数
                     */
                    refreshCounterValue(nodeCountRecorder, v);
                    refreshCounterValue(nodeCountRecorder, w);
                    refreshCounterValue(nodeCountRecorder, p);
                    /**
                     * 更新每条边记录的三角形个数
                     */
                    refreshCounterValue(edgeCountRecorder, edgeVW.getId());
                    refreshCounterValue(edgeCountRecorder, edgeVP.getId());
                    refreshCounterValue(edgeCountRecorder, edgeWP.getId());
                    /**
                     * 更新记录的三角形个数
                     */
                    triangleCounter++;
                }
            }
        }
        /**
         * 节点记录三角形个数 需要除以6
         */
        for (Map.Entry<Integer, Integer> entry : nodeCountRecorder.entrySet()) {
            Integer nodeIndex = entry.getKey();
            Integer count = entry.getValue();
            count /= 3;
            nodeCountRecorder.put(nodeIndex, count);
            triangleNodeRankList.add(new TrianglePacket(nodeIndex, count));
        }
        /**
         * 边记录三角形个数
         */
        for (Map.Entry<Integer, Integer> entry : edgeCountRecorder.entrySet()) {
            Integer edgeIndex = entry.getKey();
            Integer count = entry.getValue();
            count /= 3;
            edgeCountRecorder.put(edgeIndex, count);
            triangleEdgeRankList.add(new TrianglePacket(edgeIndex, count));
        }
        //按照持有三角形个数 对结点进行排序
        Collections.sort(triangleNodeRankList);
        Collections.sort(triangleEdgeRankList);
        triangleCounter /= 3;
    }

    private void refreshCounterValue(HashMap<Integer, Integer> recorder, int index) {
        int val = recorder.getOrDefault(index, 0);
        val++;
        recorder.put(index, val);
    }


    /**
     * 取得图中三角形总数
     */
    public int getTotalTriangle() {
        return triangleCounter;
    }

    /**
     * 取得某个结点的三角形个数
     *
     * @param id 结点id
     */
    public int getTriangle(int id) {
        return nodeCountRecorder.getOrDefault(id, 0);
    }

    /**
     * 按照结点所持有的三角形个数 从高到低排序
     */
    public List<TrianglePacket> nodeRanks() {
        return triangleNodeRankList;
    }

    /**
     * 按照结点所持有的三角形个数 从高到低排序
     */
    public List<TrianglePacket> edgeRanks() {
        return triangleEdgeRankList;
    }

    /**
     *
     */
    public String result() {
        StringBuilder sb = new StringBuilder();
        String str = "最大'边三角计数':" + triangleEdgeRankList.get(0) + "\n";
        sb.append(str);
        str = "最小'边三角计数':" + triangleEdgeRankList.get(triangleEdgeRankList.size() - 1) + "\n";
        sb.append(str);
        int ave = 0;
        int count = 0;
        for (TrianglePacket packet : triangleEdgeRankList) {
            ave += packet.getValue();
            count++;
        }
        ave /= count;
        str = "平均'边三角计数':" + ave + "\n";
        sb.append(str);
        str = "'无边个数'：" + (int) (G.E() - triangleEdgeRankList.size()) + "\n";
        sb.append(str);
        str = "'最大'顶点三角个数'：" + triangleNodeRankList.get(0) + "\n";
        sb.append(str);
        str = "'最小'顶点三角个数'：" + triangleNodeRankList.get(triangleNodeRankList.size() - 1) + "\n";
        sb.append(str);
        str = "'三角形个数'：" + getTotalTriangle() + "\n";
        sb.append(str);
        return sb.toString();
    }

    /**
     * 删除 “v和w之间的边” 会触发这个函数来刷新局部统计的三角形的个数
     */
    public void refreshPartialTriangle(int v, int w) {
//        List<Integer> commonNeighbors = new LinkedList<>();
//        Set<Integer> set = new HashSet<>();
//        for (Integer p : G.adj(v)) {
//            set.add(p);
//        }
//        for (Integer p : G.adj(w)) {
//            if (set.contains(p)) {
//                commonNeighbors.add(p);
//            }
//        }
//        commonNeighbors.add(v);
//        commonNeighbors.add(w);
//        for (Integer p : commonNeighbors) {
//            HashSet<Integer> wSet = G.adj(p);
//            int count = 0;
//            for (Integer pw : wSet) {
//                for (Integer pp : G.adj(pw)) {
//                    if (wSet.contains(pp)) {
//                        count++;
//                    }
//                }
//            }
//            count /= 2;
//            nodeCountRecorder.put(p, count);
//        }
    }

    /**
     * 取得当前三角形个数最大的结点
     */
    public TrianglePacket getTopRank() {
        int maxCount = 0;
        int id = -1;
        TrianglePacket packet;
        for (Map.Entry<Integer, Integer> entry : nodeCountRecorder.entrySet()) {
            Integer count = entry.getValue();
            if (count > maxCount) {
                id = entry.getKey();
                maxCount = count;
            }
        }
        packet = new TrianglePacket(id, maxCount);
        return packet;
    }

    /**
     * w结点是 v结点的 邻接边
     * 得到拥有三角形数最多的 v - w
     * 并将w作为返回值
     */
    public int getMaxTriangleEdgeNeighbor(int v) {
//        HashSet<Integer> wSet = G.adj(v);
//        int maxTriangle = 0;
//        int maxWid = -1;
//        for (Integer w : wSet) {
//            int count = 0;
//            for (Integer p : G.adj(w)) {
//                if (p == w || p == v || !wSet.contains(p)) {
//                    continue;
//                }
//                count++;
//            }
//            if (count > maxTriangle) {
//                maxTriangle = count;
//                maxWid = w;
//            }
//        }
//        return maxWid;
        return 0;
    }

    /**
     * @return 零节点的个数
     */
    public int zeroCount() {
        return G.nodeLength() - nodeCountRecorder.size();
    }
}
